package com.snap.vseries.analyze;

public class SavitzkyGolay {

    private double[] coeffs;

    public SavitzkyGolay(int filterWidth, int derivativeOrder, int polynomialOrder) {
        if (filterWidth % 2 == 0) {
            --filterWidth;
        }

        int filterWidth_2 = (filterWidth - 1) / 2;

        try {
            this.coeffs = savgol(polynomialOrder, filterWidth_2, filterWidth - 1 - filterWidth_2, derivativeOrder);
        } catch (Exception var6) {
        }

    }

    public static double[] applyFilter(double[] signal, double[] coeffs) {
        int signalLength = signal.length;
        if (coeffs == null) {
            return null;
        } else {
            int coeffsLength = coeffs.length;
            int middle = coeffsLength / 2;
            double[] derivative = new double[signalLength];
            double[] result = new double[signalLength + coeffsLength - 1];

            int i;
            for (i = 0; i < coeffsLength; ++i) {
                for (int j = 0; j < signalLength; ++j) {
                    result[i + j] += signal[j] * coeffs[i];
                }
            }

            for (i = 0; i < signalLength; ++i) {
                derivative[i] = result[i + middle];
            }

            for (i = 0; i < middle; ++i) {
                derivative[i] = 0.0D;
            }

            for (i = signalLength - middle; i < signalLength; ++i) {
                derivative[i] = 0.0D;
            }

            return derivative;
        }
    }

    public static float[] applyFilter(float[] signal, double[] coeffs) {
        int signalLength = signal.length;
        if (coeffs == null) {
            return null;
        } else {
            int coeffsLength = coeffs.length;
            int middle = coeffsLength / 2;
            float[] derivative = new float[signalLength];
            double[] result = new double[signalLength + coeffsLength - 1];

            int i;
            for (i = 0; i < coeffsLength; ++i) {
                for (int j = 0; j < signalLength; ++j) {
                    result[i + j] += (double) signal[j] * coeffs[i];
                }
            }

            for (i = 0; i < signalLength; ++i) {
                derivative[i] = (float) result[i + middle];
            }

            for (i = 0; i < middle; ++i) {
                derivative[i] = 0.0F;
            }

            for (i = signalLength - middle; i < signalLength; ++i) {
                derivative[i] = 0.0F;
            }

            return derivative;
        }
    }

    public static float[] calculateCoefficients(int filterWidth, int derivativeOrder, int polynomialOrder) {
        float[] flArray = null;

        try {
            double[] dblArray = savgol(polynomialOrder, (filterWidth - 1) / 2, (filterWidth - 1) / 2, derivativeOrder);
            flArray = new float[dblArray.length];

            for (int i = 0; i < flArray.length; ++i) {
                flArray[i] = (float) dblArray[i];
            }
        } catch (Exception var6) {
        }

        return flArray;
    }

    public static double[] savgol(int m, int nl, int nr, int ld) throws Exception {
        if (nl >= 0 && nr >= 0 && ld <= m && nl + nr >= m) {
            int[] indx = new int[m + 2];
            double[][] a = new double[m + 2][m + 2];
            double[] b = new double[m + 2];
            int[] d = new int[2];
            int np = nl + nr + 1;
            double[] c = new double[np + 1];

            int k;
            int mm;
            double sum;
            for (int ipj = 0; ipj <= m << 1; ++ipj) {
                sum = ipj != 0 ? 0.0D : 1.0D;

                for (k = 1; k <= nr; ++k) {
                    sum += StrictMath.pow((double) k, (double) ipj);
                }

                for (k = 1; k <= nl; ++k) {
                    sum += StrictMath.pow((double) (-k), (double) ipj);
                }

                mm = StrictMath.min(ipj, 2 * m - ipj);

                for (int imj = -mm; imj <= mm; imj += 2) {
                    a[1 + (ipj + imj) / 2][1 + (ipj - imj) / 2] = sum;
                }
            }

            ludcmp(a, m + 1, indx, d);

            for (int j = 1; j <= m + 1; ++j) {
                b[j] = 0.0D;
            }

            b[ld + 1] = 1.0D;
            lubksb(a, m + 1, indx, b);

            int kk;
            for (kk = 1; kk <= np; ++kk) {
                c[kk] = 0.0D;
            }

            for (k = -nl; k <= nr; ++k) {
                sum = b[1];
                double fac = 1.0D;

                for (mm = 1; mm <= m; ++mm) {
                    sum += b[mm + 1] * (fac *= (double) k);
                }

                kk = (np - k) % np + 1;
                c[kk] = sum;
            }

            double[] result = new double[np];
            int np_2 = (np + 1) / 2;
            double[] result_left = subArray(c, np_2 + 1, np);
            double[] result_right = subArray(c, 1, np_2);

            int i;
            for (i = 0; i < np_2 - 1; ++i) {
                result[i] = result_left[i];
            }

            for (i = np_2 - 1; i < np; ++i) {
                result[i] = result_right[i - np_2 + 1];
            }

            if (ld != 0) {
                double multiplier = 1.0D;

                for (i = ld; i >= 1; --i) {
                    multiplier *= (double) i;
                }

                for (i = 0; i < np; ++i) {
                    result[i] *= multiplier;
                }
            }

            return result;
        } else {
            throw new Exception("bad args in savgol");
        }
    }

    public static double[] subArray(double[] array, int beginPos, int endPos) {
        int start = beginPos;
        double[] sub = new double[endPos - beginPos + 1];

        for (int i = 0; i < sub.length; ++i) {
            sub[i] = array[start];
            ++start;
        }
        return sub;
    }

    public static void ludcmp(double[][] D, int n, int[] I, int[] Q) throws Exception {
        double TINY = 1.0E-20D;
        int imax = -1;
        double[] vv = new double[n + 1];
        Q[1] = 1;

        int i;
        int j;
        double big;
        for (i = 1; i <= n; ++i) {
            big = 0.0D;

            for (j = 1; j <= n; ++j) {
                double temp;
                if ((temp = Math.abs(D[i][j])) > big) {
                    big = temp;
                }
            }

            if (big == 0.0D) {
                throw new Exception("ludcmp - Singular matrix in LU decomposition.");
            }
            vv[i] = 1.0D / big;
        }

        for (j = 1; j <= n; ++j) {
            int k;
            double sum;
            for (i = 1; i < j; ++i) {
                sum = D[i][j];

                for (k = 1; k < i; ++k) {
                    sum -= D[i][k] * D[k][j];
                }
                D[i][j] = sum;
            }

            big = 0.0D;

            double dum;
            for (i = j; i <= n; ++i) {
                sum = D[i][j];

                for (k = 1; k < j; ++k) {
                    sum -= D[i][k] * D[k][j];
                }

                D[i][j] = sum;
                if ((dum = vv[i] * Math.abs(sum)) >= big) {
                    big = dum;
                    imax = i;
                }
            }

            if (j != imax) {
                for (k = 1; k <= n; ++k) {
                    dum = D[imax][k];
                    D[imax][k] = D[j][k];
                    D[j][k] = dum;
                }

                Q[1] = -Q[1];
                vv[imax] = vv[j];
            }

            I[j] = imax;
            if (D[j][j] == 0.0D) {
                D[j][j] = 1.0E-20D;
            }

            if (j != n) {
                dum = 1.0D / D[j][j];

                for (i = j + 1; i <= n; ++i) {
                    D[i][j] *= dum;
                }
            }
        }
    }

    public static void lubksb(double[][] D, int n, int[] I, double[] B) {
        int ii = 0;

        int i;
        int j;
        double s;
        for (i = 1; i <= n; ++i) {
            int ip = I[i];
            s = B[ip];
            B[ip] = B[i];
            if (ii != 0) {
                for (j = ii; j <= i - 1; ++j) {
                    s -= D[i][j] * B[j];
                }
            } else if (s != 0.0D) {
                ii = i;
            }

            B[i] = s;
        }

        for (i = n; i >= 1; --i) {
            s = B[i];

            for (j = i + 1; j <= n; ++j) {
                s -= D[i][j] * B[j];
            }

            B[i] = s / D[i][i];
        }
    }

    public double[] applyFilter(double[] signal) {
        return applyFilter(signal, this.coeffs);
    }

    public float[] applyFilter(float[] signal) {
        return applyFilter(signal, this.coeffs);
    }

    public double[] applyFilter(int[] signal) {
        double[] doubleSignal = new double[signal.length];

        for (int i = 0; i < signal.length; ++i) {
            doubleSignal[i] = (double) signal[i];
        }

        return applyFilter(doubleSignal, this.coeffs);
    }

    public int getFilterWidth() {
        return this.coeffs.length - 1;
    }
}
